import { _decorator, Component, Node, UITransform, Sprite, Color, Prefab, instantiate, Vec3, SpriteFrame, view, BoxCollider2D, Contact2DType, Collider2D, IPhysics2DContact, Vec2, PhysicsSystem2D, ERigidBody2DType, RigidBody2D } from 'cc';
import { MathUtils } from '../Utilities/MathUtils';
const { ccclass, property } = _decorator;

/**
 * 地图管理器
 * 功能：
 * 1. 根据指定大小创建基础地图
 * 2. 控制地图移动，保持玩家在屏幕中心
 * 3. 管理障碍物的生成和位置
 * 4. 严格的边界检测，阻止玩家移出地图
 */
@ccclass('MapManager')
export class MapManager extends Component {
    /**
     * 玩家节点 - 游戏中的玩家角色
     */
    @property({
        type: Node,
        tooltip: "玩家角色节点"
    })
    private player: Node = null;
    
    /**
     * 障碍物预制体数组 - 用于随机生成障碍物
     */
    @property({
        type: [Prefab],
        tooltip: "障碍物预制体数组，用于随机生成障碍物"
    })
    private obstaclePrefabs: Prefab[] = [];
    
    /**
     * 地图尺寸 - 可玩区域的大小
     */
    @property({
        tooltip: "地图的尺寸（宽度和高度相同）",
        range: [500, 5000],
        slide: true
    })
    private mapSize: number = 2000;
    
    /**
     * 地图颜色 - 地图的底色
     */
    @property({
        type: Color,
        tooltip: "地图的底色"
    })
    private mapColor: Color = new Color(40, 40, 50, 255);
    
    /**
     * 边界颜色 - 边界的颜色
     */
    @property({
        type: Color,
        tooltip: "地图边界的颜色"
    })
    private boundaryColor: Color = new Color(0, 0, 0, 255);
    
    /**
     * 地图背景精灵 - 可选的地图背景图片
     */
    @property({
        type: SpriteFrame,
        tooltip: "地图背景图片(可选)"
    })
    private mapBackground: SpriteFrame = null;
    
    /**
     * 障碍物数量 - 地图上生成的障碍物总数
     */
    @property({
        tooltip: "地图上生成的障碍物总数",
        range: [0, 1000],
        slide: true
    })
    private obstacleCount: number = 100;
    
    /**
     * 障碍物安全距离 - 障碍物与玩家初始位置的最小距离
     */
    @property({
        tooltip: "障碍物与玩家初始位置的最小距离"
    })
    private obstacleSafeDistance: number = 100;
    
    /**
     * 玩家移动速度
     */
    @property({
        tooltip: "玩家移动速度",
        range: [50, 500],
        slide: true
    })
    private moveSpeed: number = 200;
    
    /**
     * 边界检测缓冲区 - 离边界多近时停止
     */
    @property({
        tooltip: "边界检测缓冲区（越小越接近边界）",
        range: [0, 100],
        slide: true
    })
    private boundaryBuffer: number = 50;
    
    /**
     * 障碍物种子 - 用于伪随机生成障碍物
     */
    @property({
        tooltip: "障碍物伪随机生成种子",
        range: [0, 10000],
        slide: true
    })
    private obstacleSeed: number = 1234;
    
    /**
     * 障碍物碰撞组
     */
    @property({
        tooltip: "障碍物碰撞组",
        range: [0, 32],
    })
    private obstacleCollisionGroup: number = 1;
    
    /**
     * 玩家碰撞组
     */
    @property({
        tooltip: "玩家碰撞组",
        range: [0, 32],
    })
    private playerCollisionGroup: number = 2;
    
    // 内部节点引用
    private _groundNode: Node = null;    // 地图主体节点
    private _boundaryNode: Node = null;  // 边界节点
    private _obstaclesNode: Node = null; // 障碍物容器节点
    
    // 移动相关变量
    private _isMoving: boolean = false;
    private _moveDirection: Vec3 = new Vec3(0, 0, 0);
    private _lastPlayerPosition: Vec3 = new Vec3(0, 0, 0);
    private _isAtBoundary: boolean = false;
    
    /**
     * 组件加载时执行
     */
    onLoad() {
        // 启用物理系统
        PhysicsSystem2D.instance.enable = true;
        
        // 设置重力为0，我们不需要重力影响
        PhysicsSystem2D.instance.gravity = new Vec2(0, 0);
        
        // 注册全局碰撞回调
        PhysicsSystem2D.instance.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        
        // 创建地图节点
        this._createMapNodes();
        
        // 初始化地图
        this._initMap();
        
        // 生成障碍物
        this._generateObstacles();
        
        // 设置玩家碰撞
        this._setupPlayerCollision();
        
        // 保存玩家初始位置
        if (this.player) {
            this._lastPlayerPosition = this.player.getPosition().clone();
        }
        
        // 初始化地图和玩家位置
        this._resetMapPosition();
    }
    
    /**
     * 创建所需的地图节点
     */
    private _createMapNodes() {
        // 创建边界节点
        this._boundaryNode = new Node('Boundary');
        this.node.addChild(this._boundaryNode);
        this._boundaryNode.setSiblingIndex(0); // 设置渲染层级最底层
        
        // 创建地图主体节点
        this._groundNode = new Node('Ground');
        this.node.addChild(this._groundNode);
        this._groundNode.setSiblingIndex(1); // 地图在边界上方
        
        // 创建障碍物容器节点
        this._obstaclesNode = new Node('Obstacles');
        this.node.addChild(this._obstaclesNode);
        this._obstaclesNode.setSiblingIndex(2); // 障碍物在最上方
        
        console.log('地图节点创建完成');
    }
    
    /**
     * 初始化地图和边界
     */
    private _initMap() {
        // 边界尺寸比地图略大
        const boundarySize = this.mapSize + 400;
        
        // 设置地图大小
        const groundTransform = this._groundNode.getComponent(UITransform) || this._groundNode.addComponent(UITransform);
        groundTransform.setContentSize(this.mapSize, this.mapSize);
        
        // 添加精灵组件
        const groundSprite = this._groundNode.getComponent(Sprite) || this._groundNode.addComponent(Sprite);
        
        // 如果有背景图片，则使用背景图片
        if (this.mapBackground) {
            groundSprite.spriteFrame = this.mapBackground;
            groundSprite.type = Sprite.Type.SIMPLE;
            groundSprite.sizeMode = Sprite.SizeMode.CUSTOM;
        } else {
            // 否则使用纯色背景
            groundSprite.color = this.mapColor;
        }
        
        // 设置边界大小和颜色
        const boundaryTransform = this._boundaryNode.getComponent(UITransform) || this._boundaryNode.addComponent(UITransform);
        boundaryTransform.setContentSize(boundarySize, boundarySize);
        
        const boundarySprite = this._boundaryNode.getComponent(Sprite) || this._boundaryNode.addComponent(Sprite);
        boundarySprite.color = this.boundaryColor;
        
        console.log(`地图初始化完成，尺寸：${this.mapSize}x${this.mapSize}`);
    }
    
    /**
     * 重置地图和玩家位置
     */
    private _resetMapPosition() {
        if (!this.player) return;
        
        // 将玩家放在原点（屏幕中心）
        this.player.setPosition(Vec3.ZERO);
        this._lastPlayerPosition = Vec3.ZERO.clone();
        
        // 将地图也放在原点
        this.node.setPosition(Vec3.ZERO);
        
        console.log('重置地图和玩家位置');
    }
    
    /**
     * 随机生成障碍物
     */
    private _generateObstacles() {
        if (this.obstaclePrefabs.length === 0) {
            console.warn('没有设置障碍物预制体，无法生成障碍物');
            return;
        }
        
        // 清除现有障碍物
        this._obstaclesNode.removeAllChildren();
        
        const halfMapSize = this.mapSize / 2;
        
        // 使用种子来保证每次生成相同的随机序列
        let currentSeed = this.obstacleSeed;
        
        // 生成指定数量的障碍物
        for (let i = 0; i < this.obstacleCount; i++) {
            // 使用伪随机数选择障碍物预制体
            currentSeed = Math.floor(MathUtils.pseudoRandom(currentSeed) * 100000);
            const prefabIndex = Math.floor(MathUtils.pseudoRandom(currentSeed) * this.obstaclePrefabs.length);
            const obstaclePrefab = this.obstaclePrefabs[prefabIndex];
            
            if (!obstaclePrefab) continue;
            
            // 实例化障碍物
            const obstacle = instantiate(obstaclePrefab);
            this._obstaclesNode.addChild(obstacle);
            
            // 随机位置
            let x, y;
            do {
                // 更新种子
                currentSeed = Math.floor(MathUtils.pseudoRandom(currentSeed) * 100000);
                
                // 使用伪随机生成器在地图范围内随机位置
                x = (MathUtils.pseudoRandom(currentSeed) * 2 - 1) * (halfMapSize - 50);
                
                currentSeed = Math.floor(MathUtils.pseudoRandom(currentSeed) * 100000);
                y = (MathUtils.pseudoRandom(currentSeed) * 2 - 1) * (halfMapSize - 50);
                
                // 检查与玩家的距离
                const distToPlayer = Math.sqrt(x * x + y * y);
                
                // 如果距离玩家足够远，接受这个位置
                if (distToPlayer > this.obstacleSafeDistance) {
                    break;
                }
                
                // 更新种子以获取新位置
                currentSeed = Math.floor(MathUtils.pseudoRandom(currentSeed) * 100000);
            } while (true);
            
            // 设置位置
            obstacle.setPosition(new Vec3(x, y, 0));
            
            // 添加碰撞器
            this._addColliderToObstacle(obstacle);
        }
        
        console.log(`生成了 ${this.obstacleCount} 个障碍物，使用种子 ${this.obstacleSeed}`);
        
        // 确保玩家也有碰撞检测
        this._setupPlayerCollision();
    }
    
    /**
     * 全局碰撞检测回调
     */
    onBeginContact(a: Collider2D, b: Collider2D, contact: IPhysics2DContact | null) {
        // 检查是否是玩家和障碍物的碰撞
        if ((a.node === this.player && b.node.parent === this._obstaclesNode) || 
            (b.node === this.player && a.node.parent === this._obstaclesNode)) {
            
            // 找出哪个是玩家，哪个是障碍物
            const playerCollider = a.node === this.player ? a : b;
            const obstacleCollider = a.node === this.player ? b : a;
            
            console.log('玩家与障碍物碰撞');
            
            // 停止玩家移动
            this._isMoving = false;
            this._moveDirection = Vec3.ZERO.clone();
            
            // 计算推开方向
            if (contact) {
                const worldManifold = contact.getWorldManifold();
                const normal = worldManifold.normal;
                
                // 根据碰撞法线计算推开方向
                // 如果玩家是第二个碰撞体，需要反转法线方向
                const pushDir = playerCollider === b ? normal.clone() : normal.multiplyScalar(-1);
                
                // 把玩家推开一点以避免卡在障碍物内
                const pushDistance = 5; // 推开距离
                
                // 更新地图位置，使玩家离开障碍物
                this.node.position = new Vec3(
                    this.node.position.x + pushDir.x * pushDistance,
                    this.node.position.y + pushDir.y * pushDistance,
                    this.node.position.z
                );
                
                console.log(`碰撞推开，方向: (${pushDir.x.toFixed(2)}, ${pushDir.y.toFixed(2)})`);
            }
            
            // 防止卡住，立即更新玩家中心位置
            this._keepPlayerCentered();
        }
    }
    
    /**
     * 为障碍物添加碰撞器
     */
    private _addColliderToObstacle(obstacle: Node) {
        // 清除已有的碰撞器
        const existingCollider = obstacle.getComponent(BoxCollider2D);
        if (existingCollider) {
            obstacle.removeComponent(BoxCollider2D);
        }
        
        // 添加刚体组件
        let body = obstacle.getComponent(RigidBody2D);
        if (!body) {
            body = obstacle.addComponent(RigidBody2D);
            body.type = ERigidBody2DType.Static; // 静态刚体
            body.allowSleep = false;
            body.awakeOnLoad = true;
            body.gravityScale = 0; // 无重力影响
        }
        
        // 添加新碰撞器
        const collider = obstacle.addComponent(BoxCollider2D);
        
        // 获取障碍物尺寸
        const obstacleTransform = obstacle.getComponent(UITransform);
        if (obstacleTransform) {
            // 使用与视觉完全匹配的碰撞区域
            collider.size.width = obstacleTransform.width;
            collider.size.height = obstacleTransform.height;
            
            // 确保碰撞中心与障碍物中心对齐
            collider.offset = new Vec2(0, 0);
        } else {
            // 默认碰撞大小
            collider.size.width = 64;
            collider.size.height = 64;
        }
        
        // 设置碰撞属性
        collider.group = this.obstacleCollisionGroup;
        collider.density = 1.0;
        collider.friction = 0.2;
        collider.restitution = 0.1; // 轻微反弹
        collider.sensor = false; // 不是传感器，会产生实际碰撞
        collider.enabled = true;
        
        // 隔离检测 - 确保障碍物间不会碰撞
        collider.tag = 1; // 使用tag代替mask
        
        console.log(`设置障碍物碰撞器: ${obstacle.name}, 尺寸: ${collider.size.width}x${collider.size.height}`);
    }
    
    /**
     * 设置玩家碰撞组件
     */
    private _setupPlayerCollision() {
        if (!this.player) return;
        
        // 清除已有的碰撞器
        const existingCollider = this.player.getComponent(BoxCollider2D);
        if (existingCollider) {
            this.player.removeComponent(BoxCollider2D);
        }
        
        // 添加刚体
        let playerBody = this.player.getComponent(RigidBody2D);
        if (!playerBody) {
            playerBody = this.player.addComponent(RigidBody2D);
            playerBody.type = ERigidBody2DType.Kinematic; // 动力学刚体
            playerBody.allowSleep = false;
            playerBody.fixedRotation = true; // 禁止旋转
            playerBody.gravityScale = 0; // 无重力
            playerBody.linearDamping = 0.8; // 一些阻尼
        }
        
        // 添加新碰撞器
        const playerCollider = this.player.addComponent(BoxCollider2D);
        
        // 获取玩家尺寸
        const playerTransform = this.player.getComponent(UITransform);
        if (playerTransform) {
            // 碰撞尺寸与玩家精灵完全匹配
            playerCollider.size.width = playerTransform.width;
            playerCollider.size.height = playerTransform.height;
            
            // 确保碰撞体在中心
            playerCollider.offset = new Vec2(0, 0);
        } else {
            // 默认碰撞大小
            playerCollider.size.width = 50;
            playerCollider.size.height = 50;
        }
        
        // 设置碰撞属性
        playerCollider.group = this.playerCollisionGroup;
        playerCollider.density = 1.0;
        playerCollider.friction = 0.0; // 无摩擦
        playerCollider.restitution = 0.1; // 轻微反弹
        playerCollider.enabled = true;
        
        // 玩家只与障碍物碰撞
        playerCollider.tag = 2; // 使用tag代替mask
        
        console.log('设置玩家碰撞组件完成');
    }
    
    /**
     * 每帧更新
     * @param dt 帧间隔时间
     */
    update(dt: number) {
        if (!this.player || !this._groundNode) return;
        
        // 1. 获取当前玩家和地图位置
        const playerPos = this.player.getPosition();
        const mapPos = this.node.getPosition();
        
        // 2. 获取地图尺寸
        const groundTransform = this._groundNode.getComponent(UITransform);
        if (!groundTransform) return;
        
        const groundWidth = groundTransform.width;
        const groundHeight = groundTransform.height;
        const halfWidth = groundWidth / 2;
        const halfHeight = groundHeight / 2;
        
        // 3. 计算玩家在世界坐标系中的位置
        const worldPlayerX = -mapPos.x;
        const worldPlayerY = -mapPos.y;
        
        // 4. 强制边界检测 - 如果超出边界，立即修正位置
        let needCorrection = false;
        let correctionX = mapPos.x;
        let correctionY = mapPos.y;
        
        // 右边界检测
        if (worldPlayerX > halfWidth) {
            correctionX = -(halfWidth);
            needCorrection = true;
        }
        // 左边界检测
        else if (worldPlayerX < -halfWidth) {
            correctionX = halfWidth;
            needCorrection = true;
        }
        
        // 上边界检测
        if (worldPlayerY > halfHeight) {
            correctionY = -(halfHeight);
            needCorrection = true;
        }
        // 下边界检测
        else if (worldPlayerY < -halfHeight) {
            correctionY = halfHeight;
            needCorrection = true;
        }
        
        // 5. 如果需要修正，直接设置正确位置
        if (needCorrection) {
            this.node.setPosition(new Vec3(correctionX, correctionY, mapPos.z));
            this._isMoving = false; // 停止移动
        }
        
        // 6. 移动处理
        if (this._isMoving && !this._isAtBoundary) {
            // 移动前先检查是否会超出边界
            const moveX = this._moveDirection.x * this.moveSpeed * dt;
            const moveY = this._moveDirection.y * this.moveSpeed * dt;
            
            // 计算移动后的位置
            const newWorldX = worldPlayerX + moveX;
            const newWorldY = worldPlayerY + moveY;
            
            // 检查是否会超出边界
            let canMoveX = true;
            let canMoveY = true;
            
            // 横向边界检测
            if ((newWorldX > halfWidth - 5 && moveX > 0) || 
                (newWorldX < -halfWidth + 5 && moveX < 0)) {
                canMoveX = false;
                this._isAtBoundary = true;
            }
            
            // 纵向边界检测
            if ((newWorldY > halfHeight - 5 && moveY > 0) || 
                (newWorldY < -halfHeight + 5 && moveY < 0)) {
                canMoveY = false;
                this._isAtBoundary = true;
            }
            
            // 根据边界检测结果移动
            if (canMoveX && canMoveY) {
                // 可以自由移动
                this.node.position = new Vec3(
                    mapPos.x - moveX,
                    mapPos.y - moveY,
                    mapPos.z
                );
            } else if (canMoveX) {
                // 只能横向移动
                this.node.position = new Vec3(
                    mapPos.x - moveX,
                    mapPos.y,
                    mapPos.z
                );
            } else if (canMoveY) {
                // 只能纵向移动
                this.node.position = new Vec3(
                    mapPos.x,
                    mapPos.y - moveY,
                    mapPos.z
                );
            }
        }
        
        // 7. 保持玩家在屏幕中心
        this._keepPlayerCentered();
    }
    
    /**
     * 保持玩家在屏幕中心
     */
    private _keepPlayerCentered() {
        if (!this.player) return;
        
        // 检查玩家是否移动了
        const currentPosition = this.player.getPosition();
        if (Vec3.strictEquals(currentPosition, this._lastPlayerPosition)) return;
        
        // 计算玩家偏移了多少
        const offsetX = currentPosition.x - this._lastPlayerPosition.x;
        const offsetY = currentPosition.y - this._lastPlayerPosition.y;
        
        if (offsetX === 0 && offsetY === 0) return;
        
        // 将玩家还原到原来位置
        this.player.setPosition(this._lastPlayerPosition.clone());
        
        // 移动地图以抵消玩家移动
        const mapPosition = this.node.getPosition();
        this.node.setPosition(new Vec3(
            mapPosition.x - offsetX,
            mapPosition.y - offsetY,
            mapPosition.z
        ));
    }
    
    /**
     * 设置移动状态 - 用于遥感控制调用
     * @param direction 移动方向向量
     */
    public startMove(direction: Vec3) {
        if (!direction) {
            console.error("移动方向不能为null");
            return;
        }
        
        // 确保方向向量已归一化
        if (direction.x !== 0 || direction.y !== 0) {
            this._moveDirection = direction.normalize();
        } else {
            this._moveDirection = Vec3.ZERO.clone();
        }
        
        this._isMoving = true;
    }
    
    /**
     * 停止移动
     */
    public stopMove() {
        this._isMoving = false;
        this._moveDirection = Vec3.ZERO.clone();
    }
    
    /**
     * 获取地图尺寸
     */
    public getMapSize(): number {
        return this.mapSize;
    }
    
    /**
     * 重新生成障碍物
     * @param count 可选，新的障碍物数量
     */
    public regenerateObstacles(count?: number) {
        if (count !== undefined) {
            this.obstacleCount = count;
        }
        this._generateObstacles();
    }
    
    /**
     * 设置地图尺寸
     * @param size 新的地图尺寸
     */
    public setMapSize(size: number) {
        this.mapSize = size;
        
        // 重新初始化地图
        this._initMap();
        
        // 重新生成障碍物
        this._generateObstacles();
        
        // 重置位置
        this._resetMapPosition();
    }
    
    /**
     * 判断玩家是否处于边界
     */
    public isPlayerAtBoundary(): boolean {
        return this._isAtBoundary;
    }
} 